The EISA interrupt priority level is used to specify the interrupt IRQ number for the device. Its range is IRQ0-IRQ15, excluding IRQ2, which is used to cascade the interrupt controllers. EISA directly associates the interrupt priority to the IRQ input line. See the Intel 82357 Specification or the EISA Technical Reference Guide for a description of the priority ordering scheme.
There are two system resources that need to be reserved by some EISA/ISA drivers: interrupt request inputs (IRQ's) and DMA channels. Instead of pre-allocating these in the system file, a dynamic allocation scheme hands them out to the driver at initialization time. The driver is responsible for specifying which choices for IRQs and DMA channels are acceptable for the particular hardware. The operating system uses the appropriate allocation routine to assign them to the driver, which then uses the returned value to configure the hardware to respond appropriately.
The value must be selected from IRQ 3-7, 9-12, 14, and 15. All EISA interrupts are channeled into one CPU interrupt level. The priority of this CPU interrupt is below that of the clock and at the same level as on-board devices. Although the EISA interrupt is generated at the same level, it is serviced when the CPU services EISA interrupts. It services the EISA-bus interrupts in order of their EISA-bus priority, at least in that order when multiple devices interrupt at the same time.
func passes arg as an argument when called. Typically, arg corresponds to the ctlr number of the device.eisa_ivec_set (vint_t adapter, int irq, void (func*)(), int arg);
The process for allocating a DMA channel is similar to that for obtaining an interrupt number. The call to the eisa_dmachan_alloc() routine uses an 8-bit mask to represent DMA channels zero through seven. Note that bit four must always be masked because that channel is unavailable for a card's case. The value returned by the channel allocation routine is then saved to program the device to transfer data on that particular channel, as specified in the section describing the EISA DMA utility functions.
The following example is a possible outline initialization routine for the EISA device module declared in the previous section about the system files:
#include <sys/types.h> #include <sys/edt.h> #include <sys/pio.h> #include <sys/eisa.h> #include <sys/cmn_err.h> struct edrv_info { caddr_t e_addr[NBASE]; int e_dmachan; } einfo[4]; #define CARD_ID 0x0163b30a #define IRQ_MASK 0x0018 #define DMACHAN_MASK 0x7a edrv_edtinit(edt_t *e) { int iospace, eirq, edma_chan; struct edrv_info *einf; piomap_t *pmap; einf = &einfo[e->e_ctlr]; /* map address spaces */ for (iospace = 0; iospace < NBASE; iospace++) { if (!e->e_space[iospace].ios_iopaddr) break; pmap = pio_mapalloc(e->e_bus_type, e->e_adap, &e->e_space[iospace], PIOMAP_FIXED, "edrv"); einf->e_addr[iospace] = pio_mapaddr(pmap, e->e_space[iospace].ios_iopaddr); } /* should mark not-present somewhere */ return; } /* Initialize Interrupt Vector */ eirq = eisa_ivec_alloc(e->e_adap, IRQ_MASK, EISA_EDGE_IRQ); if (eirq < 0) { cmn_err(CE_WARN, "edrv: ctlr %d could not allocate IRQ\n", e->e_ctlr); /* should mark unavailable */ return; } eisa_ivec_set(e->e_adap, eirq, edrv_intr, e->e_ctlr); /* Allocate DMA Channel */ edma_chan = eisa_dmachan_alloc(e->e_adap, DMACHAN_MASK); if (edma_chan < 0) { cmn_err(CE_WARN, "edrv: ctlr %d could not allocate DMA Chan\n", e->e_ctlr); /* should mark unavailable */ return; } einf->e_dmachan = edma_chan; }